package vn.mahjonggame.game.request;

import java.util.Iterator;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.log4j.Logger;

import vn.mahjonggame.game.Mahjong;
import vn.mahjonggame.game.MahjongExtension;
import vn.mahjonggame.metadata.GameActionType;
import vn.mahjonggame.metadata.Player;
import vn.mahjonggame.metadata.PlayerMode;
import vn.mahjonggame.metadata.MObject;
import vn.mahjonggame.metadata.Response;
import vn.mahjonggame.metadata.RoomVarName;
import vn.mahjonggame.metadata.TileSet;
import vn.mahjonggame.metadata.UserVarName;
import vn.mahjonggame.platform.GameplayConfig;
import vn.mahjonggame.platform.PlatformClient;

import com.smartfoxserver.v2.entities.Room;
import com.smartfoxserver.v2.entities.User;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSArray;
import com.smartfoxserver.v2.entities.data.SFSObject;
import com.smartfoxserver.v2.extensions.BaseClientRequestHandler;
import com.smartfoxserver.v2.extensions.ExtensionLogLevel;

public class CancelRonHandler extends BaseClientRequestHandler {

	@Override
	public void handleClientRequest(User user, ISFSObject params) {
		
		final MahjongExtension ext = (MahjongExtension) getParentExtension();
		Mahjong mahjong = ext.getMahjong();
		List<User> users = user.getLastJoinedRoom().getUserList();		
		Logger logger = mahjong.getLogger();
		Player player = mahjong.getPlayerById(user.getId());		
		Player thrownPlayer = mahjong.getThrownPlayer();
		Player nextPlayerOfThrownPlayer = mahjong.getNextPlayer(thrownPlayer);
		List<Player> players = mahjong.getPlayers();
		
		Room room = ext.getGameRoom();
		
		/*
		 * Reset the player's timer
		 */
		player.cancelTimer();
		
		List<Player> canCallRonPlayers = mahjong.getCanCallRonPlayers();
		canCallRonPlayers.remove(player);		
		
		logger.info(mahjong.log(room, player, GameActionType.cancelRon.toString(), "Remove " + player.toString() + " from " + mahjong.getCanCallRonPlayers()));
		logger.info("User: " + user.getName() + "("+ user.getId() +")");
		
		/*
		 * Increase the number of player that called RON, this values is used to determine if the mahjong is drawn
		 */
		int numRonPlayer = mahjong.getNumRonPlayer();
		if(canCallRonPlayers.size() > 0){
			numRonPlayer++;
			mahjong.setNumRonPlayer(numRonPlayer);	
		}		
		
		/*
		 * The player has NOT called RON
		 */
		player.setRon(false);		
							
		Response.Builder response = new Response.Builder();
		SFSArray sfsPlayerArray = new SFSArray();
		
		Response.Builder object = new Response.Builder();
		object.winPos(player.getPlayerPosition())
				.losePos(player.getPlayerPosition())
				.loseTile(-1)
				.winTile(-1);
		
		/*
		 * Check if the Mahjong is HOA
		 */
		int numPickedDeathTile = mahjong.getPickedDeathTile().size();
		
		if(numRonPlayer == 3 
				|| (mahjong.getCalledRiichiPlayers().size() == Mahjong.NUM_OF_PLAYER && mahjong.getCalledRonPlayers().size() == 0) 
				|| numPickedDeathTile == 4 ) {
			
			
			for(int i = 0; i < players.size(); i++){
				
				Player iPlayer = players.get(i);				
				Response.Builder sfsUser = new Response.Builder();
				sfsUser.name(iPlayer.getName())
						.point(0)
						.money(0)
						.isWinner(false)
						.tiles(mahjong.tileArrayToTileIdArray(iPlayer.getLeftTiles()));
				logger.info(mahjong.log(room, player, GameActionType.cancelRon.toString(), "Player " + iPlayer.toString() + " " + iPlayer.getLeftTiles()));
				sfsPlayerArray.addSFSObject(sfsUser.build().getSFSObject());
			}
			
			object.type(1);
			response.HOA(object.build().getSFSObject())
					.players(sfsPlayerArray);
						
			send(TileSet.HOA.toString(), response.build().getSFSObject(), users);			
			logger.info(mahjong.log(room, player, GameActionType.cancelRon.toString(), "Mahjong is HOA"));
			
			//mahjong.resetTimer();			
			return;
		}
				
		int roomBet = room.getVariable(RoomVarName.roomBet.toString()).getIntValue();
		
		if(canCallRonPlayers.size() == numRonPlayer){
			if(mahjong.isHasPlayerCalledRon()){
				/*
				 * The player that call RON will win 
				 */
				if (mahjong.getCalledRonPlayers().size() > 0 && mahjong.getCalledRonPlayers().size() < 3){

					/*
					 * Calculate HAN score for each RON-ing player
					 */
					for(Iterator<Player> iPlayers = canCallRonPlayers.iterator(); iPlayers.hasNext();){
						Player iPlayer = iPlayers.next();
						if(!iPlayer.isRon()) continue;
						//mahjong.calculateHanScore(iPlayer, tile); //This is calculated on ThrowTile
						mahjong.calculateFuScore(iPlayer);
						mahjong.calculateScore(iPlayer);
						
						logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "HAN SCORE: " + iPlayer.getHanScore()));
						logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "YAKU: " + iPlayer.getYakuList()));
						logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "YAKUMAN: " + iPlayer.getYakumanList()));
						logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "OTHER YAKUMAN: " + iPlayer.getOtherYakumanList()));
						logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "FU SCORE: " + iPlayer.getFuScore()));					
						logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "SCORE: " + iPlayer.getScore()));
						
						double score = iPlayer.getScore();
						
						if(iPlayer.getPlayerPosition() != 0){
							double finalScore = thrownPlayer.getFinalScore();
							finalScore = finalScore - (score * 4);						
							thrownPlayer.setExtendedScore(-(score * 4));
							thrownPlayer.setFinalScore(finalScore);						
							
							finalScore = iPlayer.getFinalScore();
							finalScore = finalScore + (score * 4);
							iPlayer.setExtendedScore(score * 4);
							iPlayer.setFinalScore(finalScore);						
													
						}
						else {
							double finalScore = thrownPlayer.getFinalScore();
							finalScore = finalScore - (score * 6);
							thrownPlayer.setExtendedScore(-(score * 6));
							thrownPlayer.setFinalScore(finalScore);
							
							finalScore = iPlayer.getFinalScore();
							finalScore = finalScore + (score * 6);
							iPlayer.setExtendedScore(score * 6);
							iPlayer.setFinalScore(finalScore);
						}
					}
					
					/*
					 * Build the amount of each player to send to API server
					 */
					SFSArray userAmounts = new SFSArray();					
					for(int i = 0; i < users.size(); i++){
						User iUser = users.get(i);
						Response.Builder userAmount = new Response.Builder();
						Player iPlayer = mahjong.getPlayerById(iUser.getId());
						userAmount.user_id(iUser.getName());
										
						double amount = (iPlayer.getExtendedScore() * roomBet) / Double.valueOf(room.getVariable(RoomVarName.init_score.toString()).getStringValue());
						userAmount.amount(amount);						
						
						userAmounts.addSFSObject(userAmount.build().getSFSObject());
					}
					
					/*
					 * Call game_finish_game API
					 */
					if (ext.getPlayerMode() == PlayerMode.REAL_MODE.ordinal()){
						SFSObject res = mahjong.gameFinishGame(player, GameActionType.cancelRon.toString());				
						if(res != null){
							send(GameActionType.cancelRon.toString(), res, users);
							return;
						}
					}
					
					for(int i = 0; i < players.size(); i++){
											
						Player iPlayer = players.get(i);
						User iUser = mahjong.getUserByPlayerId(iPlayer.getPlayerId(), users);
						
						Response.Builder sfsUser = new Response.Builder();						
						
						if(ext.getPlayerMode() == PlayerMode.REAL_MODE.ordinal() && iUser != null){
							SFSObject res = mahjong.useGetBalance(sfsUser, iUser, iPlayer, GameActionType.callTsumo.toString());
							if(res != null){
								send(GameActionType.cancelRon.toString(), res, users);
								return;
							}
						}
						else{
							double amount = (iPlayer.getExtendedScore() * roomBet) / GameplayConfig.INIT_SCORE;
							sfsUser.money(amount);							
						}
										
						if(iPlayer.isRon()){							
							sfsUser.isWinner(true);
						}
						else {
							sfsUser.isWinner(false);							
						}									
						
						sfsUser.point(iPlayer.getExtendedScore())
								.name(iPlayer.getName())
								.tiles(mahjong.tileArrayToTileIdArray(iPlayer.getLeftTiles()));
						
						logger.info(mahjong.log(room, player, GameActionType.callRon.toString(), "Player " + iPlayer.toString() + " " + iPlayer.getLeftTiles()));
						sfsPlayerArray.addSFSObject(sfsUser.build().getSFSObject());
					}
				}
			}					
		}					
		
		logger.info(mahjong.log(room, player, GameActionType.cancelRon.toString(), "playerCanCallRons: " + mahjong.getCanCallRonPlayers()));
		
		Player nextCanCallRonPlayer = mahjong.getNextCanCallRonPlayer(player);
		
		int nextTurn;
		if(nextCanCallRonPlayer == null){
			if(mahjong.isHasPlayerCalledRon()){
				nextTurn = player.getPlayerPosition();
				response.RON(object.build().getSFSObject())
						.players(sfsPlayerArray);										
			}
			else {
				Player playerTmp = mahjong.getNextPlayer(thrownPlayer);				
				player.setHasPicked(false);
				nextTurn = playerTmp.getPlayerPosition();
				mahjong.setPlayerInTurn(playerTmp);
			}					
		}
		else {
			logger.info(mahjong.log(room, player, GameActionType.cancelRon.toString(), "nextCanCallRonPlayer: " + nextCanCallRonPlayer.toString()));
			nextTurn = nextCanCallRonPlayer.getPlayerPosition();
			response.isWait(true);			
		}
		
		response.turn(nextTurn);		
		
		/*
		 * Check if the player can fall into FURITEN state
		 */
		if(!player.isRiichiWaiting()){
			player.setTempFuriten(true);
		}
		else {
			player.setForeverFuriten(true);
		}
				
		nextPlayerOfThrownPlayer.setHasPicked(false);
		
		send(GameActionType.cancelRon.toString(), response.build().getSFSObject(), users);				
		ext.addAction(user, GameActionType.cancelRon.toString());
		
		logger.info(mahjong.log(ext.getGameRoom(), player, GameActionType.cancelRon.toString(), "nextTurn: " + nextTurn));		
		
		if(nextCanCallRonPlayer != null){
			
			if(Boolean.valueOf(room.getVariable(RoomVarName.is_auto.toString()).getStringValue())){
				/*
				 * If the next turn player can call RON
				 */				
				int delay = Integer.valueOf(room.getVariable(RoomVarName.turn_time.toString()).getStringValue());			
				final SFSObject nextParams = new SFSObject();				
				nextParams.putUtfString(MObject.type.toString(), TileSet.RON.toString());				
				final User nextCanCallRonUser = mahjong.getUserByPlayerId(nextCanCallRonPlayer.getPlayerId(), users);
				logger.info(mahjong.log(room, player, GameActionType.cancelRon.toString(), "Calling pick handler: " + delay));
				Timer timer = player.getTimer();
				timer.schedule(new TimerTask() {
					  @Override
					  public void run() {
						  SkipHandler skipHandler = new SkipHandler();
						  skipHandler.skip(ext, nextCanCallRonUser, nextParams, true);								
					  }
				}, delay);			
			}
		}		
	}
}
